﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace RaisingStudio.SmallProgram.Library
{
    [SmallProgramType]
    [StructLayout(LayoutKind.Sequential)]
    public struct Primitive
    {
#if Monodevelop
		private Dictionary<object, object> _arrayMap;
        public Dictionary<object, object> ArrayMap
#else
        private Dictionary<Primitive, Primitive> _arrayMap;
        public Dictionary<Primitive, Primitive> ArrayMap
#endif
        {
            get
            {
                return this._arrayMap;
            }
        }

        private string _primitive;

        private decimal? _primitiveAsDecimal;
        internal decimal? TryGetAsDecimal()
        {
            if (this.IsEmpty)
            {
                return null;
            }
            if (!this._primitiveAsDecimal.HasValue)
            {
                decimal result = 0M;
                if (decimal.TryParse(this.AsString, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
                {
                    this._primitiveAsDecimal = new decimal?(result);
                }
            }
            return this._primitiveAsDecimal;
        }

        internal string AsString
        {
            get
            {
                if (this._primitive == null)
                {
                    if (this._primitiveAsDecimal.HasValue)
                    {
                        this._primitive = this._primitiveAsDecimal.Value.ToString();
                    }
                    if (this._arrayMap != null)
                    {
                        StringBuilder builder = new StringBuilder();
#if Monodevelop
						foreach (KeyValuePair<object, object> pair in this._arrayMap)
						{
                            builder.AppendFormat("{0}={1};", new object[] { Escape((string)pair.Key), Escape((string)pair.Value) });
                        }
#else
                        foreach (KeyValuePair<Primitive, Primitive> pair in this._arrayMap)
                        {
                            builder.AppendFormat("{0}={1};", new object[] { Escape(pair.Key), Escape(pair.Value) });
                        }
#endif
                        this._primitive = builder.ToString();
                    }
                }
                return this._primitive;
            }
        }
        internal bool IsArray
        {
            get
            {
                this.ConstructArrayMap();
                return (this._arrayMap.Count > 0);
            }
        }
        internal bool IsEmpty
        {
            get
            {
                return ((string.IsNullOrEmpty(this._primitive) && !this._primitiveAsDecimal.HasValue) && ((this._arrayMap == null) || (this._arrayMap.Count == 0)));
            }
        }
        internal bool IsNumber
        {
            get
            {
                decimal result = 0M;
                return (this._primitiveAsDecimal.HasValue || decimal.TryParse(this.AsString, NumberStyles.Float, CultureInfo.InvariantCulture, out result));
            }
        }

        public Primitive(string primitiveText)
        {
            if (primitiveText == null)
            {
                throw new ArgumentNullException("primitiveText");
            }
            this._primitive = primitiveText;
            this._primitiveAsDecimal = null;
            this._arrayMap = null;
        }

        public Primitive(int primitiveInteger)
        {
            this._primitiveAsDecimal = new decimal?(primitiveInteger);
            this._primitive = null;
            this._arrayMap = null;
        }

        public Primitive(decimal primitiveDecimal)
        {
            this._primitiveAsDecimal = new decimal?(primitiveDecimal);
            this._primitive = null;
            this._arrayMap = null;
        }

        public Primitive(float primitiveFloat)
            : this((decimal)primitiveFloat)
        {
        }

        public Primitive(double primitiveDouble)
            : this((decimal)primitiveDouble)
        {
        }

        public Primitive(short primitiveShort)
            : this((int)primitiveShort)
        {
        }

        public Primitive(long primitiveLong)
        {
            this._primitiveAsDecimal = new decimal?(primitiveLong);
            this._primitive = null;
            this._arrayMap = null;
        }

        public Primitive(object primitiveObject)
        {
            this._primitive = primitiveObject.ToString();
            this._primitiveAsDecimal = null;
            this._arrayMap = null;
        }

        public Primitive(bool primitiveBool)
        {
            this._primitiveAsDecimal = null;
            if (primitiveBool)
            {
                this._primitive = "True";
            }
            else
            {
                this._primitive = "False";
            }
            this._arrayMap = null;
        }


        public Primitive this[Primitive index]
        {
            get
            {
                if (this.ContainsKey(index))
                {
#if Monodevelop
					return (Primitive)this._arrayMap[index];
#else
                    return this._arrayMap[index];
#endif
                }
                return "";
            }
            set
            {
                Primitive primitive = SetArrayValue(value, this, index);
                this._primitive = primitive._primitive;
                this._arrayMap = primitive._arrayMap;
                this._primitiveAsDecimal = primitive._primitiveAsDecimal;
            }
        }


        public Primitive Append(Primitive primitive)
        {
            return new Primitive(this.AsString + primitive.AsString);
        }

        public Primitive Add(Primitive addend)
        {
            decimal? value = this.TryGetAsDecimal();
            decimal? addendValue = addend.TryGetAsDecimal();
            if (value.HasValue && addendValue.HasValue)
            {
                return (value.Value + addendValue.Value);
            }
            return (this.AsString + addend.AsString);
        }

        public Primitive ContainsKey(Primitive key)
        {
            this.ConstructArrayMap();
            return this._arrayMap.ContainsKey(key);
        }

        public Primitive ContainsValue(Primitive value)
        {
            this.ConstructArrayMap();
            return this._arrayMap.ContainsValue(value);
        }

        public Primitive GetAllIndices()
        {
            this.ConstructArrayMap();
#if Monodevelop
			Dictionary<object, object> map = new Dictionary<object, object>(this._arrayMap.Count, PrimitiveComparer.Instance);
            int num = 1;
            foreach (object primitive in this._arrayMap.Keys)
            {
                map[num] = primitive;
                num++;
            }
#else
            Dictionary<Primitive, Primitive> map = new Dictionary<Primitive, Primitive>(this._arrayMap.Count, PrimitiveComparer.Instance);
            int num = 1;
            foreach (Primitive primitive in this._arrayMap.Keys)
            {
                map[num] = primitive;
                num++;
            }
#endif
            return ConvertFromMap(map);
        }

        public Primitive GetItemCount()
        {
            this.ConstructArrayMap();
            return this._arrayMap.Count;
        }

        public Primitive Subtract(Primitive addend)
        {
            return new Primitive(this.GetAsDecimal() - addend.GetAsDecimal());
        }

        public Primitive Multiply(Primitive multiplicand)
        {
            return new Primitive(this.GetAsDecimal() * multiplicand.GetAsDecimal());
        }

        public Primitive Divide(Primitive divisor)
        {
            if (divisor.GetAsDecimal() == 0M)
            {
                return 0;
            }
            return new Primitive(this.GetAsDecimal() / divisor.GetAsDecimal());
        }


        public bool LessThan(Primitive comparer)
        {
            return (this.GetAsDecimal() < comparer.GetAsDecimal());
        }

        public bool GreaterThan(Primitive comparer)
        {
            return (this.GetAsDecimal() > comparer.GetAsDecimal());
        }

        public bool LessThanOrEqualTo(Primitive comparer)
        {
            return (this.GetAsDecimal() <= comparer.GetAsDecimal());
        }

        public bool GreaterThanOrEqualTo(Primitive comparer)
        {
            return (this.GetAsDecimal() >= comparer.GetAsDecimal());
        }


        public bool EqualTo(Primitive comparer)
        {
            return this.Equals(comparer);
        }

        public bool NotEqualTo(Primitive comparer)
        {
            return !this.Equals(comparer);
        }


        public override bool Equals(object obj)
        {
            if (this.AsString == null)
            {
                this._primitive = "";
            }
            if (obj is Primitive)
            {
                Primitive primitive = (Primitive)obj;
                if ((((primitive.AsString != null) && (primitive.AsString.ToLower(CultureInfo.InvariantCulture) == "true")) && (this.AsString != null)) && (this.AsString.ToLower(CultureInfo.InvariantCulture) == "true"))
                {
                    return true;
                }
                if (this.IsNumber && primitive.IsNumber)
                {
                    return (this.GetAsDecimal() == primitive.GetAsDecimal());
                }
                return (this.AsString == primitive.AsString);
            }
            return false;
        }

        public override int GetHashCode()
        {
            if (this.AsString == null)
            {
                this._primitive = "";
            }
            return this.AsString.ToUpper(CultureInfo.InvariantCulture).GetHashCode();
        }


        public override string ToString()
        {
            return this.AsString;
        }
        private void ConstructArrayMap()
        {
            if (this._arrayMap == null)
            {
#if Monodevelop
				this._arrayMap = new Dictionary<object, object>(PrimitiveComparer.Instance);
#else
                this._arrayMap = new Dictionary<Primitive, Primitive>(PrimitiveComparer.Instance);
#endif
                if (!this.IsEmpty)
                {
                    char[] source = this.AsString.ToCharArray();
                    int index = 0;
                    while (true)
                    {
                        string key = Unescape(source, ref index);
                        if (string.IsNullOrEmpty(key))
                        {
                            return;
                        }
                        string value = Unescape(source, ref index);
                        if (value == null)
                        {
                            return;
                        }
                        this._arrayMap[key] = value;
                    }
                }
            }
        }

        internal decimal GetAsDecimal()
        {
            if (this.IsEmpty)
            {
                return 0M;
            }
            if (this._primitiveAsDecimal.HasValue)
            {
                return this._primitiveAsDecimal.Value;
            }
            decimal result = 0M;
            if (decimal.TryParse(this.AsString, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
            {
                this._primitiveAsDecimal = new decimal?(result);
            }
            return result;
        }

        public static bool ConvertToBoolean(Primitive primitive)
        {
            return (bool)primitive;
        }

        public static implicit operator string(Primitive primitive)
        {
            if (primitive.AsString == null)
            {
                return "";
            }
            return primitive.AsString;
        }

        public static implicit operator int(Primitive primitive)
        {
            return (int)primitive.GetAsDecimal();
        }

        public static implicit operator float(Primitive primitive)
        {
            return (float)primitive.GetAsDecimal();
        }

        public static implicit operator double(Primitive primitive)
        {
            return (double)primitive.GetAsDecimal();
        }

        public static implicit operator bool(Primitive primitive)
        {
            return ((primitive.AsString != null) && primitive.AsString.Equals("true", StringComparison.InvariantCultureIgnoreCase));
        }

        public static Primitive operator ==(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.Equals(primitive2);
        }

        public static Primitive operator !=(Primitive primitive1, Primitive primitive2)
        {
            return !primitive1.Equals(primitive2);
        }

        public static Primitive operator >(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.GreaterThan(primitive2);
        }

        public static Primitive operator >=(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.GreaterThanOrEqualTo(primitive2);
        }

        public static Primitive operator <(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.LessThan(primitive2);
        }

        public static Primitive operator <=(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.LessThanOrEqualTo(primitive2);
        }

        public static Primitive operator +(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.Add(primitive2);
        }

        public static Primitive operator -(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.Subtract(primitive2);
        }

        public static Primitive operator *(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.Multiply(primitive2);
        }

        public static Primitive operator /(Primitive primitive1, Primitive primitive2)
        {
            return primitive1.Divide(primitive2);
        }

        public static Primitive operator -(Primitive primitive)
        {
            return -primitive.GetAsDecimal();
        }

        public static Primitive operator |(Primitive primitive1, Primitive primitive2)
        {
            return op_Or(primitive1, primitive2);
        }

        public static Primitive operator &(Primitive primitive1, Primitive primitive2)
        {
            return op_And(primitive1, primitive2);
        }

        public static bool operator true(Primitive primitive)
        {
            return primitive;
        }

        public static bool operator false(Primitive primitive)
        {
            return !primitive;
        }

        public static Primitive op_And(Primitive primitive1, Primitive primitive2)
        {
            return primitive1 && primitive2;
        }
        public static Primitive op_Or(Primitive primitive1, Primitive primitive2)
        {
            return primitive1 || primitive2;
        }

        public static implicit operator Primitive(int value)
        {
            return new Primitive(value);
        }

        public static implicit operator Primitive(bool value)
        {
            return new Primitive(value);
        }

        public static implicit operator Primitive(string value)
        {
            if (value == null)
            {
                return new Primitive("");
            }
            return new Primitive(value);
        }

        public static implicit operator Primitive(double value)
        {
            return new Primitive((decimal)value);
        }

        public static implicit operator Primitive(decimal value)
        {
            return new Primitive(value);
        }

        public static implicit operator Primitive(DateTime value)
        {
            return new Primitive(value);
        }



        public static Primitive GetArrayValue(Primitive array, Primitive indexer)
        {
#if Monodevelop
			object primitive;
#else
            Primitive primitive;
#endif
            array.ConstructArrayMap();
            if (!array._arrayMap.TryGetValue(indexer, out primitive))
            {
                primitive = new Primitive();
            }
            return (Primitive)primitive;
        }

        public static Primitive SetArrayValue(Primitive value, Primitive array, Primitive indexer)
        {
            array.ConstructArrayMap();
#if Monodevelop
			Dictionary<object, object> map = new Dictionary<object, object>(array._arrayMap, PrimitiveComparer.Instance);
#else
            Dictionary<Primitive, Primitive> map = new Dictionary<Primitive, Primitive>(array._arrayMap, PrimitiveComparer.Instance);
#endif

            if (value.IsEmpty)
            {
                map.Remove(indexer);
            }
            else
            {
                map[indexer] = value;
            }
            return ConvertFromMap(map);
        }

#if Monodevelop
		public static Primitive ConvertFromMap(Dictionary<object, object> map)
        {
            Primitive primitive = new Primitive();
            primitive._primitive = null;
            primitive._primitiveAsDecimal = null;
            primitive._arrayMap = map;
            return primitive;
        }
#else
        public static Primitive ConvertFromMap(Dictionary<Primitive, Primitive> map)
        {
            Primitive primitive = new Primitive();
            primitive._primitive = null;
            primitive._primitiveAsDecimal = null;
            primitive._arrayMap = map;
            return primitive;
        }
#endif

        private static string Escape(string value)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (char c in value)
            {
                if (c == '=')
                {
                    stringBuilder.Append(@"\=");
                }
                else if (c == ';')
                {
                    stringBuilder.Append(@"\;");
                }
                else if (c == '\\')
                {
                    stringBuilder.Append(@"\\");
                }
                else
                {
                    stringBuilder.Append(c);
                }
            }
            return stringBuilder.ToString();
        }

        private static string Unescape(char[] source, ref int index)
        {
            bool flag = false;
            bool flag2 = true;
            int length = source.Length;
            StringBuilder stringBuilder = new StringBuilder();
            while (index < length)
            {
                char c = source[index];
                index++;
                if (!flag)
                {
                    if (c == '\\')
                    {
                        flag = true;
                        continue;
                    }
                    if ((c == '=') || (c == ';'))
                    {
                        break;
                    }
                }
                else
                {
                    flag = false;
                }
                flag2 = false;
                stringBuilder.Append(c);
            }
            if (flag2)
            {
                return null;
            }
            return stringBuilder.ToString();
        }

#if Monodevelop
		private class PrimitiveComparer : IEqualityComparer<object>
        {
            private static Primitive.PrimitiveComparer _instance = new Primitive.PrimitiveComparer();

            private PrimitiveComparer()
            {
            }

            public bool Equals(object x, object y)
            {
                return string.Equals(((Primitive)x).AsString, ((Primitive)y).AsString, StringComparison.InvariantCultureIgnoreCase);
            }

            public int GetHashCode(object obj)
            {
                return obj.GetHashCode();
            }

            public static Primitive.PrimitiveComparer Instance
            {
                get
                {
                    return _instance;
                }
            }
        }
#else
        private class PrimitiveComparer : IEqualityComparer<Primitive>
        {
            private static Primitive.PrimitiveComparer _instance = new Primitive.PrimitiveComparer();

            private PrimitiveComparer()
            {
            }

            public bool Equals(Primitive x, Primitive y)
            {
                return string.Equals(x.AsString, y.AsString, StringComparison.InvariantCultureIgnoreCase);
            }

            public int GetHashCode(Primitive obj)
            {
                return obj.GetHashCode();
            }

            public static Primitive.PrimitiveComparer Instance
            {
                get
                {
                    return _instance;
                }
            }
        }
#endif
    }
}

